package dao

import (
	"fmt"
	"github.com/Masterminds/squirrel"
	"github.com/gin-gonic/gin"
	"xinduobang/stock/common/fisherrors"
	"xinduobang/stock/dao/mysql"
	"xinduobang/stock/utils"
)

const (
	TABLE_PRE                              = "q_"
	TABLE_PERIOD_SKU_V2                    = "period_sku_v2"
	TABLE_PRODUCT_SKU_V2                   = "product_sku_v2"
	TABLE_SPECIFICATION                    = "specification"
	TABLE_PRODUCT_SPECIFICATION_VALUE      = "product_specification_value"
	TABLE_PERIOD                           = "period"
	TABLE_ADMINHANDLELOG                   = "admin_handle_log"
	TABLE_PERIOD_SKU_STOCK_DETAIL_V2       = "period_sku_stock_detail_v2"
	TABLE_RELATION_SKU_SPECIFICATION_VALUE = "relation_sku_specification_value"
)

type CommonDao struct {
	tableName    string
	databaseName string
	tx           *mysql.Tx
	op           *mysql.Operate
	ctx          *gin.Context
}

func (c *CommonDao) GetNameWithDatabase() string {
	return fmt.Sprintf("`%s`.`%s`", c.databaseName, c.tableName)
}

func validDatabase(dbname string) {
	if dbname == "" {
		panic(fisherrors.CodeDatabaseIsNotAllowEmpty.ToFishError())
	}
}

func validTx(tx *mysql.Tx) {
	if tx == nil {
		panic(fisherrors.CodeDatabaseIsNotAllowEmpty.ToFishError())
	}
}

func (c *CommonDao) insert(sqlStr string, args []interface{}) (affected int64, err error) {
	var op *mysql.Operate
	if c.tx == nil {
		op, err = mysql.NewOperate(c.ctx, c.databaseName)
		if err != nil {
			return
		}

		affected, err = op.Insert(sqlStr, args)
	} else {
		op = mysql.NewOperateForTx(c.ctx, c.databaseName)
		affected, err = op.InsertByTransaction(c.tx, sqlStr, args)
	}

	return
}

func (c *CommonDao) update(sqlStr string, args []interface{}) (affected int64, err error) {
	var op *mysql.Operate
	if c.tx == nil {
		op, err = mysql.NewOperate(c.ctx, c.databaseName)
		if err != nil {
			return
		}

		affected, err = op.Update(sqlStr, args)
	} else {
		op = mysql.NewOperateForTx(c.ctx, c.databaseName)
		affected, err = op.UpdateByTransaction(c.tx, sqlStr, args)
	}

	return
}

func (c *CommonDao) SetDataBase(database string) error {
	if database == "" {
		err := fisherrors.NewFishError("databaseName is empty")
		return err
	}

	c.databaseName = database
	return nil
}

func (c *CommonDao) commInsertData(tag string, data map[string]interface{}) (affected int64, err error) {
	sqlStr, args, err := squirrel.Insert(c.GetNameWithDatabase()).SetMap(data).ToSql()
	if err != nil {
		utils.Error(c.ctx, tag+" InsertData ToSql ", " err:", err.Error())
		return
	}

	// 执行查询
	affected, err = c.insert(sqlStr, args)

	if err != nil {
		utils.Error(c.ctx, tag+" InsertData", " err", err.Error())
		return
	}

	return
}

func (c *CommonDao) commUpdate(tag string, flieds map[string]interface{}, where squirrel.Eq) (affected int64, err error) {
	sqlStr, args, err := squirrel.Update(c.GetNameWithDatabase()).SetMap(flieds).Where(where).ToSql()
	if err != nil {
		return
	}
	affected, err = c.update(sqlStr, args)

	if err != nil {
		utils.Error(c.ctx, tag+" UpdateStockWithTx", " err", err.Error())
		return
	}

	return
}

func (c *CommonDao) commInsertByColumnsAndData(tag string, columns []string, data [][]interface{}) (affected int64, err error) {
	inserBuild := squirrel.Insert(c.GetNameWithDatabase()).Columns(columns...)
	for _, d := range data {
		inserBuild = inserBuild.Values(d...)
	}
	sqlStr, args, err := inserBuild.ToSql()
	if err != nil {
		utils.Error(c.ctx, tag+" InsertData ToSql ", " err:", err.Error())
		return
	}

	// 执行查询
	affected, err = c.insert(sqlStr, args)

	if err != nil {
		utils.Error(c.ctx, tag+" InsertData", " err", err.Error())
		return
	}

	return
}
